﻿using System;
using System.Collections.Generic;

namespace Tencent.OA.App
{
    /// <summary>
    /// <para> 表示一个执行任务调度的处理工厂。</para>
    /// </summary>
    public class ScheduleServiceFactory
    {
        private DateTime _created;
        private DateTime? _started;
        private DateTime? _firstExecute;
        private DateTime? _lastestExecute;
        //private DateTime _completed;
        private bool _isRunning;

        // 用于保存从配置获取或调用AddSchedule()方法添加的IScheduleService实例对象。
        //
        private Dictionary<string, ScheduleTask> _taskDictionary;

        /// <summary>
        /// 默认构造函数。
        /// </summary>
        public ScheduleServiceFactory()
        {
            this._created = DateTime.Now;
            this._taskDictionary = new Dictionary<string, ScheduleTask>();
        }

        /// <summary>
        /// 从配置中读取调度任务提供程序，并初始化执行这些任务的ScheduleTask程序，然后添加到字典集合中。
        /// </summary>
        /// <param name="start">指示是否在初始化ScheduleTask时启动其执行的服务。</param>
        private void InitializeTasks(bool start)
        {
            TencentConfigurationSectionGroup sectionGroup = TencentConfigurationSectionGroup.GetSectionGroup();
            ScheduleServiceSection schedulesSection = sectionGroup.Schedules;
            ScheduleServiceProviderElementCollection providerCollection = schedulesSection.ScheduleServiceProviders;
            if (providerCollection == null)
                return;

            int interval = 5; // schedulesSection.Interval;
            foreach (ScheduleServiceProviderElement provider in providerCollection)
            {
                Type t = provider.ScheduleServiceType;
                IScheduleService scheduleService = Activator.CreateInstance(t) as IScheduleService;
                ScheduleTask task;
                if (provider.ExecuteAbsoluteTime)
                {
                    task = new ScheduleTask(scheduleService, provider.ExecutingTime);
                }
                else
                {
                    int taskInterval = provider.Interval;
                    if (taskInterval == 0)
                        taskInterval = interval;
                    task = new ScheduleTask(scheduleService, taskInterval, provider);
                }
                this._taskDictionary[provider.ScheduleServiceName] = task;
                if (start)
                    task.Start();
            }
        }

        /// <summary>
        /// 获取对象的创建时间。
        /// </summary>
        public DateTime CreatedDatetime
        {
            get { return this._created; }
        }

        /// <summary>
        /// 获取第一个任务开始执行的时间。
        /// </summary>
        public DateTime? FirstStartDatetime
        {
            get { return this._started; }
        }

        /// <summary>
        /// 获取第一个任务的执行时间。
        /// </summary>
        public DateTime? FirstTaskExecute
        {
            get
            {
                if (this._isRunning)
                {
                    if (this._firstExecute.HasValue)
                        return this._firstExecute;

                    foreach (ScheduleTask task in this._taskDictionary.Values)
                    {
                        if ((task.FirstExecuteTime.HasValue && !this._firstExecute.HasValue) ||
                            (task.FirstExecuteTime.HasValue && this._firstExecute.HasValue && task.FirstExecuteTime.Value < this._firstExecute.Value))
                            this._firstExecute = task.FirstExecuteTime;
                    }
                }
                return this._firstExecute;
            }
        }

        /// <summary>
        /// 获取最后一个任务的执行时间。
        /// </summary>
        public DateTime? LastestTaskExecute
        {
            get
            {
                if (this._isRunning)
                {
                    foreach (ScheduleTask task in this._taskDictionary.Values)
                    {
                        if ((task.LastestCompleteTime.HasValue && !this._lastestExecute.HasValue) ||
                            (task.LastestCompleteTime.HasValue && this._lastestExecute.HasValue && task.LastestCompleteTime.Value > this._lastestExecute.Value))
                            this._lastestExecute = task.LastestCompleteTime;
                    }
                }
                return this._lastestExecute;
            }
        }

        /// <summary>
        /// <para> 确定当前的调度工厂中是否已包含指定名称的任务。</para>
        /// </summary>
        /// <param name="scheduleServiceName">任务名称</param>
        /// <returns>如果包含指定名称的任务返回true，否则返回false。</returns>
        public bool ContainsSchedule(string scheduleServiceName)
        {
            return this._taskDictionary.ContainsKey(scheduleServiceName);
        }

        /// <summary>
        /// <para> 向当前的调度工厂添加一个任务。</para>
        /// </summary>
        /// <remarks>
        /// <para> 在调用此方法添加任务之前，需调用 ContainsSchedule(string) 方法检查当前的工厂中是否已包含需要添加的任务名称。</para>
        /// <para> 通过此方法添加的任务没用启动，需要调用Start()方法来启动这些刚添加的任务；
        /// 当调用Stop()方法时将清理添加的服务资源，所以在调用Stop()方法后必须重新添加需要执行的任务。</para>
        /// </remarks>
        /// <param name="scheduleServiceName">任务名称。</param>
        /// <param name="scheduleService">需要添加的调度任务。</param>
        /// <param name="interval">执行调度任务的间隔时间。</param>
        /// <exception cref="ArgumentNullException">scheduleServiceName 为null。</exception>
        /// <exception cref="ArgumentNullException">scheduleService 为null。</exception>
        /// <exception cref="ArgumentOutOfRangeException">interval 小于等于0。</exception>
        /// <exception cref="ArgumentException"> 集合中已存在具有相同名称的任务。</exception>
        public void AddSchedule(string scheduleServiceName, IScheduleService scheduleService, int interval)
        {
            if (scheduleServiceName == null)
                throw new ArgumentNullException("scheduleServiceName");

            if (scheduleService == null)
                throw new ArgumentNullException("scheduleService");

            if (interval <= 0)
                throw new ArgumentOutOfRangeException("interval");

            ScheduleTask task = new ScheduleTask(scheduleService, interval);
            this._taskDictionary.Add(scheduleServiceName, task);
        }

        /// <summary>
        /// <para> 开始执行调度任务。在调度任务启动时，将会从配置文件中读取实现IScheduleService接口的类型，初始化这些类型后并启动服务。</para>
        /// </summary>
        public void Start()
        {
            if (!_isRunning)
            {
                if(!this._started.HasValue)
                    this._started = DateTime.Now;

                // 首先启动通过AddSchedule添加的任务，然后在从配置中读取任务并启动
                //
                foreach (ScheduleTask task in this._taskDictionary.Values)
                {
                    task.Start();
                }
                this.InitializeTasks(true);

                _isRunning = true;
            }
        }

        /// <summary>
        /// <para> 停止所有调度任务。同时将清理任务的资源。</para>
        /// </summary>
        public void Stop()
        {
            if (!_isRunning)
                return;

            foreach (ScheduleTask task in this._taskDictionary.Values)
            {
                task.ExecutiveHandle.Enabled = false;
                task.Dispose();
            }
            this.Reset();
        }

        /// <summary>
        /// <para> 暂停所有任务。</para>
        /// </summary>
        public void Pause()
        {
            if (!_isRunning)
                return;

            foreach (ScheduleTask task in this._taskDictionary.Values)
            {
                task.ExecutiveHandle.Enabled = false;
            }
        }

        /// <summary>
        /// <para> 继续所有任务。</para>
        /// </summary>
        public void Continue()
        {
            if (_isRunning)
                return;

            foreach (ScheduleTask task in this._taskDictionary.Values)
            {
                task.ExecutiveHandle.Enabled = true;
            }
        }

        private void Reset()
        {
            this._taskDictionary.Clear();
            this._isRunning = false;
            this._firstExecute = null;
            this._lastestExecute = null;
        }

        /// <summary>
        /// <para> 已重载。返回当前任务运行的状态信息。</para>
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (this._isRunning)
            {
                return string.Format("Current has {0} Schedule taskes runing, First Created: {1}, Started: {2}, FirstExecute: {3}, LastExecute: {4}, IsRunning: {5}",
                    this._taskDictionary.Count, _created, _started, this._firstExecute, this._lastestExecute, _isRunning);
            }
            return "Current Status, all task stoped.";
        }

    }
}
